package com.fjec.common.util;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 阿里云OSS文件上传工具类
 *
 */
public class AliOSSUtil {

    /**
     * 计算fileKey
     *
     * @param fileName 原始文件名
     * @return 返回fileKey
     */
    private static String getFileKey(String fileName) {
        String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
        String fileKey = OSSConfig.PIC_LOCATION + UUID.randomUUID().toString().toUpperCase().replace("-", "") + "." + fileType;
        return fileKey;
    }

    /**
     * @param file        系统文件
     * @param contentType 文件类型
     * @param fileName    原始文件名
     * @return String 文件访问地址
     * @MethodName: uploadFile
     * @Description: OSS单文件上传
     */
    public static String uploadFile(File file, String contentType, String fileName) {
        return putObject(file, contentType, getFileKey(fileName));
    }

    /**
     * @param input       系统文件流
     * @param contentType 文件类型
     * @param fileName    原始文件名
     * @return String 文件访问地址
     * @MethodName: uploadFile
     * @Description: OSS单文件上传
     */
    public static String uploadFile(InputStream input, String contentType, String fileName) {
        return putObject(input, contentType, getFileKey(fileName));
    }

    /**
     * @param file
     * @param contentType
     * @param oldUrl
     * @return String
     * @MethodName: updateFile
     * @Description: 更新文件:只更新内容，不更新文件名和文件地址。
     * (因为地址没变，可能存在浏览器原数据缓存，不能及时加载新数据，例如图片更新，请注意)
     */
    public static String updateFile(File file, String contentType, String oldUrl) {
        String fileName = getFileName(oldUrl);
        if (fileName == null) return null;
        return putObject(file, contentType, fileName);
    }

    /**
     * @param fileUrl 需要删除的文件url
     * @return boolean 是否删除成功
     * @MethodName: deleteFile
     * @Description: 单文件删除
     */
    public static boolean deleteFile(String fileUrl) {
        String bucketName = AliOSSUtil.getBucketName(fileUrl);       //根据url获取bucketName
        String fileName = AliOSSUtil.getFileName(fileUrl);           //根据url获取fileName
        if (bucketName == null || fileName == null) return false;
        OSSClient ossClient = null;
        try {
            ossClient = new OSSClient(OSSConfig.END_POINT, OSSConfig.ACCESS_KEY_ID, OSSConfig.ACCESS_KEY_SECRET);
            GenericRequest request = new DeleteObjectsRequest(bucketName).withKey(fileName);
            ossClient.deleteObject(request);
        } catch (Exception oe) {
            oe.printStackTrace();
            return false;
        } finally {
            ossClient.shutdown();
        }
        return true;
    }

    /**
     * @param fileUrls 需要删除的文件url集合
     * @return int 成功删除的个数
     * @MethodName: batchDeleteFiles
     * @Description: 批量文件删除(较快)：适用于相同endPoint和BucketName
     */
    public static int deleteFile(List<String> fileUrls) {
        int deleteCount = 0;    //成功删除的个数  
        String bucketName = AliOSSUtil.getBucketName(fileUrls.get(0));       //根据url获取bucketName
        List<String> fileNames = AliOSSUtil.getFileName(fileUrls);         //根据url获取fileName
        if (bucketName == null || fileNames.size() <= 0) return 0;
        OSSClient ossClient = null;
        try {
            ossClient = new OSSClient(OSSConfig.END_POINT, OSSConfig.ACCESS_KEY_ID, OSSConfig.ACCESS_KEY_SECRET);
            DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName).withKeys(fileNames);
            DeleteObjectsResult result = ossClient.deleteObjects(request);
            deleteCount = result.getDeletedObjects().size();
        } catch (OSSException oe) {
            oe.printStackTrace();
            throw new RuntimeException("OSS服务异常:", oe);
        } catch (ClientException ce) {
            ce.printStackTrace();
            throw new RuntimeException("OSS客户端异常:", ce);
        } finally {
            ossClient.shutdown();
        }
        return deleteCount;

    }

    /**
     * @param fileUrls 需要删除的文件url集合
     * @return int 成功删除的个数
     * @MethodName: batchDeleteFiles
     * @Description: 批量文件删除(较慢)：适用于不同endPoint和BucketName
     */
    public static int deleteFiles(List<String> fileUrls) {
        int count = 0;
        for (String url : fileUrls) {
            if (deleteFile(url)) {
                count++;
            }
        }
        return count;
    }

    private static String putObject(File file, String contentType, String fileName) {
        InputStream input = null;
        try {
            input = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        }
        return putObject(input, contentType, fileName);
    }

    /**
     * @param fileName
     * @return String
     * @MethodName: putObject
     * @Description: 上传文件
     */
    private static String putObject(InputStream input, String contentType, String fileName) {
        String url = null;      //默认null  
        OSSClient ossClient = null;
        try {
            ossClient = new OSSClient(OSSConfig.END_POINT, OSSConfig.ACCESS_KEY_ID, OSSConfig.ACCESS_KEY_SECRET);
            //创建上传Object的Metadata  
            ObjectMetadata meta = new ObjectMetadata();
            //设置上传内容类型  
            meta.setContentType(contentType);
            //被下载时网页的缓存行为    
            meta.setCacheControl("no-cache");
            //创建上传请求  
            PutObjectRequest request = new PutObjectRequest(OSSConfig.BUCKET_NAME, fileName, input, meta);
            ossClient.putObject(request);
            //上传成功再返回的文件路径  
            //url = OSSConfig.END_POINT.replaceFirst("http://","http://"+OSSConfig.BUCKET_NAME+".")+"/"+fileName;
            url = "http://" + OSSConfig.BUCKET_NAME + "." + OSSConfig.BUC_KET + "/" + fileName;
        } catch (OSSException oe) {
            oe.printStackTrace();
            return null;
        } catch (ClientException ce) {
            ce.printStackTrace();
            return null;
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            ossClient.shutdown();
        }
        return url;
    }

    public static byte[] getObject(String fileUrl) {
        OSSClient ossClient = null;
        try {
            ossClient = new OSSClient(OSSConfig.END_POINT, OSSConfig.ACCESS_KEY_ID, OSSConfig.ACCESS_KEY_SECRET);
            //创建上传请求
            GetObjectRequest request = new GetObjectRequest(OSSConfig.BUCKET_NAME, getFileName(fileUrl));
            OSSObject result = ossClient.getObject(request);
            return IOUtils.toByteArray(result.getObjectContent());
        } catch (OSSException oe) {
            oe.printStackTrace();
        } catch (ClientException ce) {
            ce.printStackTrace();
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            ossClient.shutdown();
        }
        return null;
    }

    public static interface CallBack {
        public void doCallBack(InputStream stream);
    }

    /**
     * @param fileUrl 文件url
     * @return String bucketName
     * @MethodName: getBucketName
     * @Description: 根据url获取bucketName
     */
    private static String getBucketName(String fileUrl) {
        String http = "http://";
        String https = "https://";
        int httpIndex = fileUrl.indexOf(http);
        int httpsIndex = fileUrl.indexOf(https);
        int startIndex = 0;
        if (httpIndex == -1) {
            if (httpsIndex == -1) {
                return null;
            } else {
                startIndex = httpsIndex + https.length();
            }
        } else {
            startIndex = httpIndex + http.length();
        }
        int endIndex = fileUrl.indexOf(".oss-");
        return fileUrl.substring(startIndex, endIndex);
    }

    /**
     * @param fileUrl 文件url
     * @return String fileName
     * @MethodName: getFileName
     * @Description: 根据url获取fileName
     */
    public static String getFileName(String fileUrl) {
        String str = "aliyuncs.com/";
        int beginIndex = fileUrl.indexOf(str);
        if (beginIndex == -1) return null;
        return fileUrl.substring(beginIndex + str.length());
    }

    /**
     * @param fileUrls 文件url
     * @return List<String>  fileName集合
     * @MethodName: getFileName
     * @Description: 根据url获取fileNames集合
     */
    private static List<String> getFileName(List<String> fileUrls) {
        List<String> names = new ArrayList<String>();
        for (String url : fileUrls) {
            names.add(getFileName(url));
        }
        return names;
    }

}  